#include "instructions/control/control.h"
#include "instructions/base/branch_logic.h"

namespace jvm {
namespace instructions {

// GOTO implementation
void GOTO::execute(std::shared_ptr<rtda::Frame> frame) {
    branch(frame, getOffset());
}

// TABLE_SWITCH implementation
void TABLE_SWITCH::fetchOperands(std::shared_ptr<BytecodeReader> reader) {
    reader->skipPadding();
    _defaultOffset = reader->readInt32();
    _low = reader->readInt32();
    _high = reader->readInt32();
    int32_t jumpOffsetsCount = _high - _low + 1;
    _jumpOffsets = reader->readInt32s(jumpOffsetsCount);
}

void TABLE_SWITCH::execute(std::shared_ptr<rtda::Frame> frame) {
    int32_t index = frame->getOperandStack()->popInt();
    int32_t offset;

    if (index >= _low && index <= _high) {
        offset = _jumpOffsets[index - _low];
    } else {
        offset = _defaultOffset;
    }

    branch(frame, offset);
}

// LOOKUP_SWITCH implementation
void LOOKUP_SWITCH::fetchOperands(std::shared_ptr<BytecodeReader> reader) {
    reader->skipPadding();
    _defaultOffset = reader->readInt32();
    _npairs = reader->readInt32();
    _matchOffsets = reader->readInt32s(_npairs * 2);
}

void LOOKUP_SWITCH::execute(std::shared_ptr<rtda::Frame> frame) {
    int32_t key = frame->getOperandStack()->popInt();

    for (int32_t i = 0; i < _npairs * 2; i += 2) {
        if (_matchOffsets[i] == key) {
            int32_t offset = _matchOffsets[i + 1];
            branch(frame, offset);
            return;
        }
    }

    branch(frame, _defaultOffset);
}

} // namespace instructions
} // namespace jvm